package com.hhwy.framework.persistent;

import java.lang.annotation.Annotation;
import java.lang.reflect.Field;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.Id;
import javax.persistence.ManyToMany;
import javax.persistence.ManyToOne;
import javax.persistence.OneToMany;
import javax.persistence.OneToOne;

import com.hhwy.framework.annotation.PropertyDesc;
import com.hhwy.framework.persistent.entity.DProperty;
import com.hhwy.framework.persistent.entity.DRelation;
import com.hhwy.framework.persistent.entity.DomainInfo;

import net.sf.ehcache.Cache;
import net.sf.ehcache.CacheManager;
import net.sf.ehcache.Ehcache;
import net.sf.ehcache.Element;
import net.sf.ehcache.config.CacheConfiguration;

public class VOCache {
static CacheManager cacheManger = CacheManager.getInstance();
	
	static Ehcache voCache ;
	static{
		cacheManger.removeCache("voCache");
		CacheConfiguration voConfig = new CacheConfiguration();
		voConfig.setName("voCache");
		voConfig.setMaxEntriesLocalHeap(50000);
		voConfig.setEternal(false);
		voCache = new Cache(voConfig);
		cacheManger.addCache(voCache);
		
	}
	/**
	 * 
	 * @param key
	 * @param value
	 */
	public static void addDomainInfo(String key , DomainInfo value){
		
		voCache.put(new Element(key, value));
	}
	/**
	 * 获取所有实体信息
	 * @return
	 */
	public static DomainInfo[] getAllDoaminInfo(){
		
		return (DomainInfo[])getAll(voCache);
	}
	public static DomainInfo getDomainInfo(String key){
		if(voCache.get( key) != null)
			return (DomainInfo)voCache.get( key).getObjectValue();
		else
			return null;
	}	/**
	 * 获取所有实体信息
	 * @return
	 */
	public static Object[] getAll(Ehcache cache){
		@SuppressWarnings("unchecked")
		List<String> keyList =cache.getKeys();
		DomainInfo[] eis = new DomainInfo[keyList.size()];
		for (int i = 0; i < eis.length; i++) {
			eis[i] = (DomainInfo) cache.get(keyList.get(i)).getObjectValue();
		}
		return eis ;
	}
	/**
	 * 
	 * getDomainInfo(获取实体定义信息)<br/>
	 * @param clazz
	 * @return
	 * @throws InstantiationException
	 * @throws IllegalAccessException 
	 * DomainInfo
	 * @exception 
	 * @since  1.0.0
	 */
	public static DomainInfo getDomainInfo(@SuppressWarnings("rawtypes") Class clazz ) throws InstantiationException, IllegalAccessException{
		DomainInfo domainInfo = getDomainInfo(clazz.getName());
		if(domainInfo != null)
			return domainInfo;
		
		DomainInfo di = readDomainInfo(clazz);
		addDomainInfo(clazz.getName(), di);
		
		return di;
	}

	private static DomainInfo readDomainInfo(Class<?> clazz)
			throws InstantiationException, IllegalAccessException {
		Field[] fields = clazz.getDeclaredFields();
		Object obj = clazz.newInstance();
		Map<String, DProperty> propertyMap = new HashMap<String, DProperty>();
		Map<String, DRelation> relationMap = new HashMap<String, DRelation>();
		for (int j = 0; j < fields.length; j++) {
			Annotation[] annos = fields[j].getAnnotations();
			String fieldName = fields[j].getName();

			if (fields[j].getType().equals(String.class)
					|| fields[j].getType().equals(Boolean.class)
					|| fields[j].getType().equals(Long.class)
					|| fields[j].getType().equals(Integer.class)
					|| fields[j].getType().equals(Double.class)
					|| fields[j].getType().equals(java.sql.Timestamp.class)) {

				DProperty property = null;
				boolean pk = false;
				String type = fields[j].getType().getSimpleName();
				int length = 32;
				int precision = 0;
				// FIXME 从实体类定义中找出属性的默认值
				String defaultValue = getDefaultValue(fields[j], obj);
				boolean nullable = true;

				String geometryType = "";
				String desc = "";
				boolean isFile=false;
				String dict = "";
				String dateFormat = "";
				for (int k = 0; k < annos.length; k++) {

					// 主键字段
					if (annos[k].annotationType().equals(Id.class)) {
						pk = true;
					}
					if (annos[k].annotationType().equals(Column.class)) {
						Column column = (Column) annos[k];
						length = column.length();
						precision = column.precision();
						nullable = column.nullable();
					}
					if (annos[k].annotationType().equals(PropertyDesc.class)) {
						PropertyDesc pDesc = (PropertyDesc) annos[k];
						geometryType = pDesc.type();
						desc = pDesc.desc();
						isFile = pDesc.isFile();
						dict = pDesc.dict();
						dateFormat = pDesc.dateFormat();
					}

				}
				property = new DProperty(fieldName, "", pk, type, length,
						precision, defaultValue, nullable, geometryType, desc,
						isFile ,dict,dateFormat);

				propertyMap.put(fieldName, property);
			} else {
				DRelation relation = null;
				for (int l = 0; l < annos.length; l++) {
					String relationType = null;
					String cascade = "ALL";
					String fetch = "LAZY";
					String mappedBy = "";
					String targetClass = "";
					String targetProperty = "id";
					// 一对一关系
					if (annos[l].annotationType().equals(OneToOne.class)) {
						OneToOne oto = (OneToOne) annos[l];
						relationType = oto.annotationType().getSimpleName();
						cascade = oto.cascade().toString();
						fetch = oto.fetch().toString();
						mappedBy = oto.mappedBy();
						targetClass = oto.targetEntity().getName();
					}
					// 多对多关系
					if (annos[l].annotationType().equals(ManyToMany.class)) {
						ManyToMany mtm = (ManyToMany) annos[l];
						relationType = mtm.annotationType().getSimpleName();
						cascade = mtm.cascade().toString();
						fetch = mtm.fetch().toString();
						mappedBy = mtm.mappedBy();
						targetClass = mtm.targetEntity().getName();

					}
					// 一对多关系
					if (annos[l].annotationType().equals(OneToMany.class)) {
						OneToMany otm = (OneToMany) annos[l];
						relationType = otm.annotationType().getSimpleName();
						cascade = otm.cascade().toString();
						fetch = otm.fetch().toString();
						mappedBy = otm.mappedBy();
						targetClass = otm.targetEntity().getName();
					}
					// 多对一关系
					if (annos[l].annotationType().equals(ManyToOne.class)) {
						ManyToOne mto = (ManyToOne) annos[l];
						relationType = mto.annotationType().getSimpleName();
						cascade = mto.cascade().toString();
						fetch = mto.fetch().toString();
						targetClass = mto.targetEntity().getName();

					}
					Class<?> relationClass = fields[j].getType();
					String type = clazz.getName();
					relation = new DRelation(fieldName, type, relationType,
							cascade, fetch, mappedBy, targetClass,
							targetProperty, relationClass);
					relationMap.put(fieldName, relation);
				}
			}
		}
		return new DomainInfo(clazz, getEntityName(clazz), propertyMap,
				relationMap);
	}
	/**
	 * getEntityName(描述这个方法的作用)<br/>
	 * @param clazz
	 * @return 
	 * String
	 * @exception 
	 * @since  1.0.0
	*/
	private static String getEntityName(Class<?> clazz) {
		String entityName = null;
		Annotation[] annos = clazz.getAnnotations();
		for (int i = 0; i < annos.length; i++) {
			if(annos[i].annotationType().equals(Entity.class)){
				entityName = ((Entity)annos[i]).name();
				break;
			}
		}
		if(entityName == null )
			entityName = clazz.getSimpleName();
		
		
		return entityName;
	}
	/**
	 * 获取属性的默认值
	 * 
	 * @param field
	 * @param obj
	 * @return
	 * @throws IllegalArgumentException
	 * @throws IllegalAccessException
	 */
	private static String getDefaultValue(Field field, Object obj)
			throws IllegalArgumentException, IllegalAccessException {
		if (boolean.class.equals(field.getDeclaringClass())) {
			return String.valueOf(field.getBoolean(obj));
		} else if (float.class.equals(field.getDeclaringClass())) {
			return String.valueOf(field.getFloat(obj));

		} else if (double.class.equals(field.getDeclaringClass())) {
			return String.valueOf(field.getDouble(obj));
		} else if (byte.class.equals(field.getDeclaringClass())) {
			return String.valueOf(field.getByte(obj));

		} else if (char.class.equals(field.getDeclaringClass())) {
			return String.valueOf(field.getChar(obj));

		} else if (int.class.equals(field.getDeclaringClass())) {
			return String.valueOf(field.getInt(obj));

		} else if (short.class.equals(field.getDeclaringClass())) {
			return String.valueOf(field.getShort(obj));
		} else if (long.class.equals(field.getDeclaringClass())) {
			return String.valueOf(field.getLong(obj));

		} else if (String.class.equals(field.getDeclaringClass())) {
			return String.valueOf(field.get(obj));

		} else

			return "";
	}

}
